/*
 * MyGWT User Extensions
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package net.mygwt.ux.client.widgets.wizard;

import java.util.Iterator;

import net.mygwt.ui.client.Style;
import net.mygwt.ui.client.event.BaseEvent;
import net.mygwt.ui.client.event.SelectionListener;
import net.mygwt.ui.client.widget.Button;
import net.mygwt.ui.client.widget.ButtonBar;
import net.mygwt.ui.client.widget.Shell;
import net.mygwt.ui.client.widget.WidgetContainer;
import net.mygwt.ui.client.widget.layout.BorderLayout;
import net.mygwt.ui.client.widget.layout.BorderLayoutData;

import com.google.gwt.user.client.DOM;
import com.google.gwt.user.client.Element;
import com.google.gwt.user.client.ui.DeckPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.VerticalPanel;

/**
 * 
 * @author Chris Worley
 *
 */
public class WizardDialog extends Shell {

  /**
   * Button listener
   * 
   */
  private class ButtonListener implements SelectionListener {
    public void widgetSelected(BaseEvent be) {
      buttonPressed(be);
    }
  }

  /** wizard */
  private Wizard wizard;

  /** image element */
  private Element imageElement;

  /** current page */
  private WizardPage currentPage;

  /** button listener */
  private ButtonListener buttonListener = new ButtonListener();

  /** button panel */
  private ButtonBar buttonBar = new ButtonBar();

  /** deck panel for wizard pages */
  private DeckPanel pagePanel;

  /** page title */
  private Label pageTitleLabel;

  /** message label */
  private Label messageLabel;

  /** cancel button */
  private Button cancelButton;

  /** finish button */
  private Button finishButton;

  /** previous button */
  private Button previousButton;

  /** next button */
  private Button nextButton;

  /**
   * Default constructor
   */
  public WizardDialog(Wizard wizard) {
    super(Style.CLOSE | Style.RESIZE);
    this.wizard = wizard;
    wizard.setWizardDialog(this);
  }

  /**
   * Add button to wizard dialog. This method will ensure the button listener is
   * set.
   * 
   * @param text
   * @return
   */
  public Button addButton(String text) {
    Button button = new Button(text);
    button.addSelectionListener(buttonListener);
    buttonBar.add(button);
    return button;
  }

  /**
   * handle button press event
   * 
   * @param be
   */
  protected void buttonPressed(BaseEvent be) {
    if (cancelButton == be.widget) {
      onCancel();
    } else if (finishButton == be.widget) {
      onFinish();
    } else if (previousButton == be.widget) {
      onPrevious();
    } else if (nextButton == be.widget) {
      onNext();
    }
  }

  /*
   * (non-Javadoc)
   * 
   * @see net.mygwt.ui.client.widget.Shell#createContent(net.mygwt.ui.client.widget.WidgetContainer)
   */
  protected void createContent(WidgetContainer container) {
    // create buttons
    previousButton = addButton("Previous");
    nextButton = addButton("Next");
    finishButton = addButton("Finish");
    cancelButton = addButton("Cancel");

    container.setLayout(new BorderLayout());

    // create message heading
    HorizontalPanel headingPanel = new HorizontalPanel();
    BorderLayoutData northData = new BorderLayoutData(Style.NORTH, 50);
    northData.setBorders(false);
    container.add(headingPanel, northData);

    headingPanel.setWidth("100%");
    imageElement = DOM.createDiv();

    VerticalPanel textPanel = new VerticalPanel();
    textPanel.setWidth("100%");
    headingPanel.add(textPanel);
    pageTitleLabel = new Label();
    messageLabel = new Label();
    textPanel.add(pageTitleLabel);
    textPanel.add(messageLabel);

    // create page panel
    pagePanel = new DeckPanel();
    BorderLayoutData pageData = new BorderLayoutData(Style.CENTER);
    pageData.setBorders(false);
    container.add(pagePanel, pageData);

    // create button bar
    BorderLayoutData buttonData = new BorderLayoutData(Style.SOUTH, 25);
    buttonData.setBorders(false);
    container.add(buttonBar, buttonData);

    // add wizard pages to page panel
    for (Iterator iter = wizard.getWizardPages().iterator(); iter.hasNext();) {
      WizardPage page = (WizardPage) iter.next();
      pagePanel.add(page);
    }

    // show first page
    showPage(wizard.getFirstPage());

    // update button enables state
    updateButtonEnabledState();
  }

  /**
   * return current wizard page
   */
  public WizardPage getCurrentWizardPage() {
    return currentPage;
  }

  /**
   * cancel button pressed
   * 
   */
  private void onCancel() {
    close();
  }

  /**
   * finish button pressed
   * 
   */
  private void onFinish() {
    // store current page
    wizard.getCurrentPage().store();

    // perform finish and close if successful
    if (wizard.performFinish()) {
      close();
    }
  }

  /**
   * next button pressed
   * 
   */
  private void onNext() {
    showPage(wizard.getNextPage());
  }

  /**
   * previous button pressed
   * 
   */
  private void onPrevious() {
    showPage(wizard.getPreviousPage());
  }

  /**
   * set page message
   * 
   * @param message
   */
  private void setMessage(String message) {
    messageLabel.setText(message);
  }

  /**
   * set page title
   */
  private void setPageTitle(String pageTitle) {
    pageTitleLabel.setText(pageTitle);
  }

  /**
   * show wizard page page must exist in the wizards list of pages
   * 
   * @param page
   */
  protected void showPage(WizardPage page) {
    // attemp to find the wizard page
    int index = wizard.getWizardPages().indexOf(page);
    if (index < 0) {
      throw new IllegalArgumentException(
          "Wizard page not found in page list, cannot show page.");
    }

    // switch pages and call supporting methods
    // store current page
    if (wizard.getCurrentPage() != null) {
      wizard.getCurrentPage().store();
      wizard.getCurrentPage().beforeHide();
    }

    page.beforeShow();
    pagePanel.showWidget(index);
    DOM.setElementAttribute(imageElement, "class", page.getIcon());
    setPageTitle(page.getPageTitle());
    setMessage(page.getMessage());
    page.populate();
    if (wizard.getCurrentPage() != null) {
      wizard.getCurrentPage().afterHide();
    }
    page.afterShow();

    currentPage = page;
    
    // update buttons
    updateButtonEnabledState();
  }

  /**
   * update buttons enabled state
   */
  private void updateButtonEnabledState() {
    WizardPage nextPage = wizard.getNextPage();
    WizardPage previousPage = wizard.getPreviousPage();

    cancelButton.setEnabled(true);
    finishButton.setEnabled(nextPage == null && wizard.canFinish());
    nextButton.setEnabled(nextPage != null);
    previousButton.setEnabled(previousPage != null);
  }
}
